#include <iostream>
#include <dpsm/StateMachine.h>

using namespace dpsm;

class State2;
class State1;
class State3;

struct finished{};
struct repeat{};
struct working{};

typedef Transition<State1, finished, State2> Transition1;
typedef Transition<State2, finished, State1> Transition2;
typedef Transition<State1, repeat, State1> Transition3;
typedef Transition<State2, working, State1> Transition4;
typedef Transition<State2, repeat, State3 > Transition5;
typedef Transition<State3 , finished, State1 > Transition6;
typedef TYPELIST_6( Transition1, Transition2, Transition3, Transition4, Transition5, Transition6 ) TransitionList;
typedef StateMachine<Transitions< TransitionList >, bool, true > Machine;

class State2 : public Machine::State{
private:
  Machine::ReturnType ExecuteStepImpl( Machine::StateHolder& stateHolder){
    static int count = 0;
    std::cout << "SecondState" << std::endl;
    count++;
    if( count < 10 )
    {
      stateHolder.SendEvent<repeat>(this, 4);
      return true;
    }
    else if( count < 20 )
    {
      stateHolder.SendEvent<finished>(this, 4);
    }
    else
    {
      return false;
    }
    
    return true;
  }
  
public:
  State2(Machine::StateHolder& stateHolder, int a):Machine::State(stateHolder){}
  ~State2(){}
};


class State1 : public Machine::State{
    const char* cout;
public:
  State1(Machine::StateHolder& stateHolder):Machine::State(stateHolder), m_counter(0){}
  State1(Machine::StateHolder& stateHolder, int arg):Machine::State(stateHolder), m_counter(arg){}
  ~State1(){}
  
private:
  Machine::ReturnType ExecuteStepImpl( Machine::StateHolder& stateHolder){
    m_counter++;
    if( m_counter == 3 ){
      stateHolder.SendEvent<finished>(this, 1);
    }else if( m_counter % 5 == 0 ){
      stateHolder.SendEvent<finished>(this, 1);
    }
    
    std::cout << "FirstState " << m_counter << std::endl;
    return true;
  }
  
private:
  int m_counter;
};


template<class T, class OriginalType>
class GenericState : public T::State
{
public:
  typedef typename T::ReturnType ReturnType;
  typedef typename T::StateHolder StateHolder;
  typedef typename T::State State;
  
private:
  ReturnType ExecuteStepImpl( StateHolder& stateHolder){
    std::cout << "Third state" << std::endl;
    stateHolder.template SendEvent<finished>(static_cast<OriginalType*>(this), 4);
    return true;
  }
  
public:
  GenericState(StateHolder& stateHolder, int a):State(stateHolder){}
  virtual ~GenericState(){}
};


class State3 : public GenericState<Machine, State3>{ 
public:
  State3(Machine::StateHolder& stateHolder, int arg) : GenericState<Machine, State3>(stateHolder, arg) {
  }
};


State1* createFirstState( Machine::StateHolder& stateHolder )
{
  return new State1(stateHolder);
}

int main(int argc, char **argv) {
    Machine machine( createFirstState );
    while(machine.ExecuteStep()){}
    return 0;
}
